package bma.common.langutil.concurrent;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import bma.common.langutil.core.ExceptionUtil;

/**
 * 定时处理器（整合对象）
 * 
 * @author 关中
 * @since 1.0 (imported from BMA.ESP Project)
 * 
 */
public class TimerManager {

	final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(TimerManager.class);

	static protected TimerManager instance;

	static public TimerManager checkInstance(TimerManager timer) {
		if (timer != null)
			return timer;
		return instance;
	}

	public static TimerManager getInstance() {
		return instance;
	}

	private long tickDuration = 100;
	private int ticksPerWheel = 512;
	private int taskInitSize = 100;
	private Executor executor;

	protected transient ProcessThread thread;

	public long getTickDuration() {
		return tickDuration;
	}

	public void setTickDuration(long tickDuration) {
		this.tickDuration = tickDuration;
	}

	public int getTicksPerWheel() {
		return ticksPerWheel;
	}

	public void setTicksPerWheel(int ticksPerWheel) {
		this.ticksPerWheel = ticksPerWheel;
	}

	public int getTaskInitSize() {
		return taskInitSize;
	}

	public void setTaskInitSize(int taskInitSize) {
		this.taskInitSize = taskInitSize;
	}

	public Executor getExecutor() {
		return executor;
	}

	public void setExecutor(Executor executor) {
		this.executor = executor;
	}

	public void startManager() {

		if (executor == null) {
			executor = Executors.newSingleThreadExecutor();
		}

		if (thread == null) {
			HashedTimeWheel wheel = new HashedTimeWheel(tickDuration,
					TimeUnit.MILLISECONDS, ticksPerWheel);
			ProcessTimeWheel p = new ProcessTimeWheel();
			p.setWheel(wheel);
			p.setInitTaskSize(taskInitSize);
			p.setExecutor(executor);

			thread = new ProcessThread("tm", p);
			Future<Boolean> f = thread.startProcess();
			try {
				Boolean r = f.get();
				if (!r.booleanValue()) {
					throw new IllegalStateException(
							"TimerManager ProcessThread startup fail");
				}
			} catch (Exception e) {
				throw ExceptionUtil.throwRuntime(e);
			}
		}

		if (instance == null) {
			instance = this;
		}
	}

	public void stopManager() {
		if (thread != null) {
			Future<Boolean> f = thread.close();
			if (f != null) {
				try {
					f.get();
				} catch (Exception e) {
				}
			}
			thread = null;
		}
	}

	public boolean postTimerTask(ProcessTimerTask task) {
		if (thread == null)
			throw new IllegalStateException("manager not start");
		return thread.postIntent(task);
	}

	public static ProcessTimerTask schedule(final Runnable r, long time) {
		return new ProcessTimerTaskAbstract(time) {
			@Override
			public void run() {
				r.run();
			}
		};
	}

	public static ProcessTimerTask scheduleSync(final Runnable r, long time) {
		return new ProcessTimerTaskAbstract(time, true) {
			@Override
			public void run() {
				r.run();
			}
		};
	}

	public static ProcessTimerTask delay(final Runnable r, long delay) {
		return new ProcessTimerTaskAbstract(System.currentTimeMillis() + delay) {
			@Override
			public void run() {
				r.run();
			}
		};
	}

	public static ProcessTimerTask delaySync(final Runnable r, long delay) {
		return new ProcessTimerTaskAbstract(System.currentTimeMillis() + delay,
				true) {
			@Override
			public void run() {
				r.run();
			}
		};
	}
}
